package com.jchy.renderit.displayable;
 
import java.util.Vector;

import com.jchy.renderit.core.Dir;
import com.jchy.renderit.core.Displayable;
import com.jchy.renderit.core.Hit;
import com.jchy.renderit.core.Point;

public class Sphere extends Displayable
{

    public Sphere()
    {
    }    

    public Hit intersect(Point prp, Point vrp)
    {
        Hit   aHit = new Hit();        
        Point utprp, utvrp, utloc, utnormpt;
        Dir   utd;

        utloc = new Point();
        utnormpt = new Point();
             
        
        utprp = untransform(prp);
        utvrp = untransform(vrp);
        utd   = utprp.toDir(utvrp);
        utd.normalize();

        double a, b, c, rt, t1, t2, t;

        // Intersect ray starting at transformed Projection Reference Point, 
        // direction towards transformed View Reference Point with 
	// Sphere of radius 1 at the origin
        a=(utd.dx*utd.dx+utd.dy*utd.dy+utd.dz*utd.dz);
        b=2*(utd.dx*utprp.x+utd.dy*utprp.y+utd.dz*utprp.z);
        c=utprp.x*utprp.x+utprp.y*utprp.y+utprp.z*utprp.z-1.0;

        if(b*b >= 4*a*c)
        { 
            rt=Math.sqrt(b*b-4*a*c);  
            t1=(-b+rt)/(2*a);
            t2=(-b-rt)/(2*a);
            
            // t1 and t2 represent the intersection with both sides of the sphere
            // A negative value means the intersection is behind the viewer
            // A lower value is the point closer to the viewer
            // A value between 0.0 and 0.00001 may be an intersection with itself
            // due to roundoff error
            // If both points are behind the viewer then "return aHit"
            // means no hit since Hit.isHit defaults to false 
            if((t1<t2)&&(t1>0.00001)) t=t1;
            else if(t2>0.00001) t=t2;
            else return aHit;

            aHit.isHit=true;
            utloc.x=utprp.x+t*utd.dx;
            utloc.y=utprp.y+t*utd.dy;
            utloc.z=utprp.z+t*utd.dz;
            aHit.color=new java.awt.Color(getPrimaryColorRed(),
                                          getPrimaryColorGreen(),
                                          getPrimaryColorBlue());

            utnormpt.x=2*utloc.x;
            utnormpt.y=2*utloc.y;
            utnormpt.z=2*utloc.z;
            
            aHit.location=transform(utloc);
            aHit.normpt=transform(utnormpt);
            aHit.ambient=ambient;
            aHit.diffuse=diffuse;
            aHit.phongCoef=phongCoef;
            aHit.phongExp=phongExp;

        }
        else aHit.isHit=false;

        return aHit;        
    }

    public Vector<Hit> allHits(Point a, Point b)
    {
    	Vector<Hit> result = new Vector<Hit>();
    	result.add(new Hit());
    	return result;
    }
    
	public boolean isInside(Point inPoint)
	{
        Point utprp = untransform(inPoint);
		
		return (utprp.x*utprp.x+utprp.y*utprp.y+utprp.z*utprp.z < 1.0);
	}
}

